package miggy.ui;

import miggy.DisassembledItem;
import miggy.MemoryDisassembler;
import miggy.cpu.Disassembler;
import miggy.SystemModel;
import miggy.utils.TextUtil;

import javax.swing.*;
import java.util.ArrayList;
import java.util.logging.Logger;

/*
//  Miggy - Java Amiga MachineCore
//  Copyright (c) 2008, Tony Headford
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//  following conditions are met:
//
//    o  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//       following disclaimer.
//    o  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
//       following disclaimer in the documentation and/or other materials provided with the distribution.
//    o  Neither the name of the Miggy Project nor the names of its contributors may be used to endorse or promote
//       products derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Revision: 21 $
*/
public class DisassemblyModel extends AbstractListModel
{
	private static Logger logger = Logger.getLogger(DisassemblyModel.class.getName());
	private static final int START_ADDR = 0;
	private static final int END_ADDR = 0x00ffffff;
	private int current_addr;
	private int size;
	private final ArrayList<DisassembledItem> items;
	private final Disassembler disasm;

	public DisassemblyModel(int slidingWindowSize)
	{
		this.size = slidingWindowSize;
		current_addr = 0;
		items = new ArrayList<DisassembledItem>();
		disasm = new MemoryDisassembler(items);
		updateAll();
	}

	public final void updateAll()
	{
		current_addr = SystemModel.CPU.getPC();
		logger.info("Thread " + Thread.currentThread().getId() + " read PC as " + TextUtil.toHex(current_addr));
		fetchItems();
	}

	public final void refresh()
	{
		fetchItems();
	}

	/**
	 * Returns the length of the list.
	 *
	 * @return the length of the list
	 */
	public final int getSize()
	{
		return size;
	}

	public final void setCurrentPos(int pos)
	{
		current_addr = pos;
		fetchItems();
	}

	public final int getCurrentPos()
	{
		return current_addr;
	}

	public final void setSlidingWindowSize(int size)
	{
		//size changes based on the size of the JList and the number of rows
		//currently visible
		if(this.size != size)
		{
			this.size = size;
			fetchItems();
		}
	}

	/**
	 * Returns the value at the specified index.
	 *
	 * @param index the requested index
	 * @return the value at <code>index</code>
	 */
	public final Object getElementAt(int index)
	{
		logger.finest("DisassemblyModel getElementAt(" + index + ")");
		return items.get(index);
	}

	private void fetchItems()
	{
		//starting at current_addr disassemble until size items have been gathered
		//or we've reached the end of memory
		logger.fine("Building DisassemblyModel");
		int start = current_addr;
		int count = 0;
		items.removeAll(items);

		try
		{
			while((start < END_ADDR) && (count < size))
			{
				start = disasm.disassemble(start);
				count++;
			}

			if(count < size)
			{
				for(;count < size; count++)
				{
					items.add(DisassembledItem.EmptyItem);
				}
			}
			
			this.fireContentsChanged(this, 0, size);
		}
		catch(IndexOutOfBoundsException e)
		{
			logger.warning("Out of bounds building DisassemblyModel @ " + TextUtil.toHex(start));
		}
	}
}
